package com.lkj.config;

import com.lkj.annotation.Autowired;
import com.lkj.annotation.Controller;
import com.lkj.annotation.RequestMapping;
import com.lkj.annotation.Service;

import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class AnnotationConfig {

    private static AnnotationConfig config;

    private static List<String> classNames = new ArrayList<String>();

    private static Map<String,Object> ioc = new HashMap<String, Object>();

    public AnnotationConfig() {
        config();
    }

    public static AnnotationConfig getInstance(){
        if (config == null) {
            return config = new AnnotationConfig();
        } else {
            return config;
        }
    }

    private void  config()  {

        String packageName = getPackageName();
        doScanner(packageName);
        doInstance();
        doAutowired();

    }

    private String getPackageName(){

        String packageName = null;
        try {
            InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("config.properties");

            Properties properties = new Properties();
            properties.load(inputStream);

            packageName = properties.getProperty("packageName");

        } catch (IOException e) {
            e.printStackTrace();
        }

        return packageName;
    }

    private void doScanner(String packageName)  {

        URL url = this.getClass().getResource("/" + packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());

        for (File file : dir.listFiles()) {

            if (file.isDirectory()){
                doScanner(packageName+"."+file.getName());
            } else {
                String className = packageName+"."+file.getName().replace(".class","");
                classNames.add(className);
            }
        }
    }

    private void  doInstance(){

        if (classNames.isEmpty()) {
            return;
        }

        for (String className : classNames) {

            try {
                Class<?> clazz = Class.forName(className);

                if (clazz.isAnnotationPresent(Controller.class)){

                    String simpleName = getLowerFirst(clazz.getSimpleName());
                    ioc.put(simpleName,clazz.newInstance());

                } else if (clazz.isAnnotationPresent(Service.class)) {

                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();

                    if ("".equals(beanName)){
                        beanName = getLowerFirst(clazz.getSimpleName());
                    }

                    Object instance = clazz.newInstance();
                    ioc.put(beanName,instance);

                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (Class<?> i : interfaces) {

                        ioc.put(i.getName(),instance);
                    }

                } else {
                    continue;
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private void doAutowired() {
        if (ioc.isEmpty()){
            return;
        }

        for (Map.Entry<String, Object> entry : ioc.entrySet()) {
            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {

                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
                Autowired autowired = field.getAnnotation(Autowired.class);
                String beanName = autowired.value();
                if ("".equals(beanName)) {
                    beanName = field.getType().getName();
                }
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(),ioc.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    public void doMapper(String url){

        if (classNames.isEmpty()){
            return;
        }

        for (String className : classNames) {

            try {
                Class<?> aClass = Class.forName(className);

                if (aClass.isAnnotationPresent(Controller.class)) {
                    RequestMapping clazzMapper = aClass.getAnnotation(RequestMapping.class);

                    for (Method method : aClass.getMethods()) {
                        if (method.isAnnotationPresent(RequestMapping.class)){
                            RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);

                            String path = clazzMapper.value()+methodMapping.value();
                            if (path.equals(url)){

                                String simpleName = getLowerFirst(aClass.getSimpleName());

                                Object res = method.invoke(ioc.get(simpleName), "lkj");
                                System.out.println(res);
                            }

                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }


        }
    }

    private String getLowerFirst(String beanName){
        char[] chars = beanName.toCharArray();
        chars[0] += 32;

        return String.valueOf(chars);
    }
}
